package com.ywicc.usblibs.utils;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.util.Log;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * author : zhouxuan77
 * e-mail : zhouxuan77@163.com
 * time   : 2022/03/22
 * desc   : USB 方法初步封装
 * version: 1.0
 */
public class UsbUtils implements UsbPermissionUtils.OnUsbPermissionListener {

    private final static String TAG = "UsbUtils";

    private final Context context;
    private final ThreadPoolExecutor threadPool;
    private final ExecutorService singleThreadExecutor;

    private UsbSerialPort ports;
    private SerialInputOutputManager outputManager;
    private UsbPermissionUtils usbPermissionUtils;
    private OnUsbDataResultListener onUsbDataResultListener;

    private byte[] sendData;
    private int intervalTime;

    public UsbUtils(Context context) {
        this.context = context;

        // 创建线程池
        threadPool = new ThreadPoolExecutor(4, 8, 0L, TimeUnit.MICROSECONDS,
                new ArrayBlockingQueue<>(5), new ThreadPoolExecutor.CallerRunsPolicy());
        singleThreadExecutor = Executors.newSingleThreadExecutor();
    }

    /**
     * 初始化 USB
     *
     * @param onUsbDataResultListener UsbUtils.OnUsbDataResultListener 对象
     * @param intervalTime            接收数据间隔时长 (多久获取一次数据)
     */
    public void initUsb(OnUsbDataResultListener onUsbDataResultListener, int intervalTime) {
        Log.v(TAG, "Start initUsb");

        this.onUsbDataResultListener = onUsbDataResultListener;
        this.intervalTime = intervalTime;

        threadPool.execute(checkPermissionRunnable);
    }

    /**
     * 设置 USB 的基础参数
     * <p>
     * 通过 {@link UsbPermissionUtils} 中的接口获得
     *
     * @param usbManager UsbManager
     * @param usbDevice  UsbDevice
     */
    private void setUsb(UsbManager usbManager, UsbDevice usbDevice) {
        Log.v(TAG, "Set USB");

        UsbDeviceConnection connection = usbManager.openDevice(usbDevice);

        List<UsbSerialDriver> drivers =
                UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);

        if (drivers.size() > 0) {
            // 优先获取第一个 USB 设备
            ports = drivers.get(0).getPorts().get(0);

            try {
                ports.open(connection);
                ports.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);

                registerListener();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发送对应的数据
     *
     * @param data 发送对应的数据 (byte 数组)
     */
    public void sendData(byte[] data) {
        sendData = data;

        threadPool.execute(sendDataRunnable);
    }

    /**
     * 注册 USB 回调数据的监听
     */
    private void registerListener() {
        if (ports != null) {
            outputManager = new SerialInputOutputManager(ports, listener);

            singleThreadExecutor.submit(outputManager);
        }
    }

    /**
     * 停止 USB 回调数据的监听
     */
    public void destroyListener() {
        onUsbDataResultListener = null;

        outputManager.stop();
        outputManager = null;

        usbPermissionUtils.stopReceiver();
    }

    /* Runnable 区域 */

    /**
     * 判断是否获取 USB 权限的 Runnable
     */
    UsbRunnableUtils.UsbRunnable checkPermissionRunnable = new UsbRunnableUtils.UsbRunnable(new UsbRunnableUtils.UsbRunnableInterface() {
        @Override
        public void run() {
            usbPermissionUtils = new UsbPermissionUtils(context);

            usbPermissionUtils.checkPermission(UsbUtils.this);
        }
    });

    /**
     * 发送数据的 Runnable
     */
    UsbRunnableUtils.UsbRunnable sendDataRunnable = new UsbRunnableUtils.UsbRunnable(new UsbRunnableUtils.UsbRunnableInterface() {
        @Override
        public void run() {
            try {
                ports.write(sendData, 5000);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

    /**
     * 接收 USB 数据接口
     */
    private final SerialInputOutputManager.Listener listener = new SerialInputOutputManager.Listener() {
        @Override
        public void onNewData(byte[] data) {
            threadPool.execute(new UsbRunnableUtils.UsbRunnable(() -> {
                if (onUsbDataResultListener != null) {
                    onUsbDataResultListener.callBackUsbRecvData(data);
                }

                // 延时
                if (intervalTime > 0) {
                    try {
                        Thread.sleep(intervalTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }));
        }

        @Override
        public void onRunError(Exception e) {
            e.printStackTrace();
        }
    };

    /**
     * 获取已获取权限的 UsbManager 和 UsbDevice
     * <p>
     * 通过 {@link UsbPermissionUtils} 中的接口获得
     */
    @Override
    public void onResult(UsbManager usbManager, UsbDevice usbDevice) {
        setUsb(usbManager, usbDevice);
    }

    /* 接口区域 */

    public interface OnUsbDataResultListener {
        void callBackUsbRecvData(byte[] data);
    }
}
